#include "aux_functions_def.hpp"
#include "aux_functions_impl.hpp"

#include "kmeans_def.hpp"
#include "kmeans_impl.hpp"

#include "kkmeans_def.hpp"
#include "kkmeans_impl.hpp"

#include "opt_kkmeans_def.hpp" // Hoping this is faster that previous version
#include "opt_kkmeans_impl.hpp"



#include "Riemann_Kernel_def.hpp"
#include "Riemann_Kernel_impl.hpp"

#include "dct_def2.hpp"
#include "dct_impl2.hpp"

//esto lo voy a hacer desde afuera. Se quitara de aca
inline  
clustering_RM::clustering_RM(  std::string in_video_path,  field<std::string> in_frames_list, uword in_ro, uword in_co, std::string in_tosavein )
:frames_list(in_frames_list), video_path( in_video_path ) , ro(in_ro) , co(in_co), tosavein (in_tosavein)
{
  //dct_frame();
  precalculate_features();
 
}


inline  
clustering_RM::clustering_RM(std::string load_ker,std::string save_part, std::string in_GT, int summ_percentage, std::string in_video_path, field<std::string> in_frames_list )
:frames_list(in_frames_list), video_path( in_video_path ), GT (in_GT)
{
 
  mat stein_ker;
  stein_ker.load(load_ker);
  int max_iter = 100;
 
  int Ncent = stein_ker.n_cols*summ_percentage/100;
  //int Ncent =10;
  run_kkmeans(stein_ker, max_iter,  Ncent, save_part) ;
  //run_kkmeans(mat K, uword max_iter, uword Ncent, std::string part_name, std::string GT)
 
}




inline  
void
clustering_RM::precalculate_features()
{
  double nf = frames_list.n_rows;
  double ni = 10; // # of consecutive images to be used to calculate the point in the manifold
 
  cout << "# images to calculate a covariance matrix (Riemmannian Manifold): " << ni << endl;
  cout << "# of frames " << nf << endl;
  double n_covMx = floor(nf/ni); // # of Covariance matrices
  cout << "# of covariance matrices is " << n_covMx << endl;
 
  field<mat> Cov_Features;
  Cov_Features.set_size(n_covMx,1); // Covariance matrices for all the segments. 1 segment = 1 second = 10 frames in UCSD dataset
  uword pos = 0;
  field<std::string>  name_frames(ni,1);
 
  for (uword f = 0; f <  n_covMx*ni; f+=ni)//  Should be nf, but iI want this to be multiple of ni (10).
    {
     
      cout << "Doing for frames " << f << "-" << f+ni-1 << endl;
      for (uword i = 0; i < ni; ++i) // Getting a set of ni (10) names to calculate the features
      {
        name_frames(i,0) = frames_list(f+i);
      }
     
      //creating_RiemmannPoint(name_frames).print("Que pasa??");
      Cov_Features(pos,0) =  creating_RiemmannPoint(name_frames);
      pos++;
      //cout << "rows: " << Cov_Features(pos,0).n_rows << " - cols: " << Cov_Features(pos,0).n_cols << endl;
    }
   
    Cov_Features.save(tosavein);
    //Cov_Features.print();
    //getchar();
}

inline  
mat
clustering_RM::creating_RiemmannPoint(field<std::string>  name_frames)
{
  uword n_frames = name_frames.n_rows;
  cv::Mat cvImage;
  double N = 8 ;
  dct2d dct(N);
  mat coef_one_frame;
  //mat F = zeros(vec_size,n_frames); //vec_size is an input
 
  double jump = 2;
  double lw = floor((co - N)/jump + 1);
  double lh = floor((ro - N)/jump + 1);
  double l  = lw*lh;
 
  mat coef_segment ; // coef for 10 frames
  coef_segment.zeros(15,l*n_frames);
 
 
  for (uword n = 0; n < n_frames;  ++n)
  {
    //cout << name_frames(n,0) << endl;
    std::stringstream tmp_name;
   
    tmp_name << video_path << name_frames(n,0);
    //cout << tmp_name.str() << endl;
    cvImage = cv::imread(tmp_name.str(), CV_LOAD_IMAGE_GRAYSCALE);
   
    /*cv::namedWindow("Image", CV_WINDOW_AUTOSIZE );
     *    cv::imshow("Image", cvImage);
     *    cv::waitKey(2);*/
   
    aux_functions aux_fx;
    mat frame;
    frame = aux_fx.convert2Arma_nor(cvImage); // hacer dentro del otro
    coef_one_frame = dct.get_coeff_overlap_6(frame); // Jumping 2 pixels & 15 coefficients
    //cout << "Rows: " << coef_one_frame.n_rows << "- Cols: " <<coef_one_frame.n_cols << endl;
   
    uword ci = l*n;
    uword  cf = (l*n+l) - 1;
    coef_segment.submat(span::all , span(ci, cf)) = coef_one_frame;
   
  }
  //getchar();
  mat Riemmannian_point = cov(coef_segment.t());
  //cout << "Coef rows: " << coef_segment.n_rows << " - Coef cols: " << coef_segment.n_cols << endl;;
  return Riemmannian_point;
}

//save_ker: to load the Kernel
//save_part: to save the partitions--Maybe I don't need it any more
//GT: load the indices of the Ground Truth
inline  
void
clustering_RM::run_kkmeans(mat K, uword max_iter, uword Ncent, std::string part_name)
{
 
  k_kmeans kkm(K, Ncent);
  kkm.calc(max_iter);
 
  vec gt_ind;
  gt_ind.load(GT);
 
  /// Selecting one segment per cluster
  double  matching_cluster = 0;
  uvec nearpoints = kkm.near_points();
  nearpoints.t().print("summary 1");
  for (uword i = 0; i < nearpoints.n_elem; ++i )
  {
    uword Rn = nearpoints(i);    
    //cout << "Gn= " << Gn << endl;
    //uvec q1 = find( gt_ind == Gn );
    double check  = gt_ind (Rn);
   
    if (check==1)
    {
      matching_cluster++;
    }
  }
 
  cout << "My summary selecting one point per cluster has: " << nearpoints.n_elem << " Grassmann Points. " << matching_cluster << " match with GT" << endl;
 
  cout << "Showing summary for 'Selecting one segment per cluster' " << endl;
  //showing_summary(nearpoints);
  //getchar();
 
 
 
  /// Selecting all points in smaller clusters
 
  //cout << "Nov 24" << endl;
  uvec rare_event = kkm.small_clusters();
 
  double  matching_clusterII = 0;
 
 
  for (uword i = 0; i < rare_event .n_elem; ++i )
  {
    uword Rn = rare_event (i);    
    //cout << "Gn= " << Gn << endl;
    //uvec q1 = find( gt_ind == Gn );
    double check  = gt_ind (Rn);
    if (check==1)
    {
      matching_clusterII++;
     
    }
  }
 
  cout << "My summary selecting all points in smaller clusters has: " << rare_event.n_elem << " Points. " << matching_clusterII << " match with GT" << endl;
 
  cout << "Showing summary for 'Selecting all points in smaller clusters' " << endl;
  //showing_summary(rare_event);
  //getchar();
  //getchar();
 
 
 
 
 
 
}


inline  
void
clustering_RM::showing_summary(uvec vec_summ)
{
  ///Showing summary
  cv::namedWindow("Image", CV_WINDOW_AUTOSIZE );
  cv::Mat show_frame;
 
  for (uword i = 0; i < vec_summ.n_elem; ++i )
  {
    double ini_frame = ( vec_summ(i)  -1 + 1)*10 + 1; // I add 1 as vec_summ starts in zero
    //cout << "ini_frame : " << ini_frame << endl;
    //cout << "vec_summ(i) " << vec_summ(i) + 1 << endl;
   
    for (int j = 0; j < 10; ++j )
    {
      std::stringstream tmp_name;
      tmp_name << video_path << "/"<<frames_list(ini_frame + j - 1, 0);
     
      //cout << tmp_name.str() << endl;
     
      show_frame = cv::imread(tmp_name.str(), CV_LOAD_IMAGE_GRAYSCALE);
      resize(show_frame, show_frame, cv::Size(240,160 ) );
     
      cv::imshow("Image", show_frame);
      cv::moveWindow("Image", 10, 50);
      cv::waitKey(50);
    }
  }
}

